package com.nervenets.web.controller.admin;

import com.nervenets.Global;
import com.nervenets.utils.JodaUtils;
import com.nervenets.utils.PropertiesLoader;
import com.nervenets.utils.StringUtils;
import com.nervenets.web.controller.BaseController;
import com.nervenets.web.controller.IdParams;
import com.nervenets.web.controller.IdTokenParams;
import com.nervenets.web.controller.TokenParams;
import com.nervenets.web.entity.KeyValue;
import com.nervenets.web.entity.MessageCode;
import com.nervenets.web.entity.UserToken;
import com.nervenets.web.enumeration.Role;
import com.nervenets.web.hibernate.dao.BuildingDao;
import com.nervenets.web.hibernate.dao.ManagerDao;
import com.nervenets.web.hibernate.domain.Building;
import com.nervenets.web.hibernate.domain.Manager;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.validation.ConstraintViolation;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Api(value = "后台用户接口v1", description = "后台用户相关接口")
@RestController
@RequestMapping("/api/v1/manager")
public class ManagerController extends BaseController {
    @Resource
    private ManagerDao managerDao;
    @Resource
    private BuildingDao buildingDao;

    @ApiOperation("后台登录")
    @PostMapping("/login")
    public String login(@RequestBody AdminLoginParams params) {
        final Set<ConstraintViolation<AdminLoginParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        Manager manager = managerDao.findManagerByMobile(params.getUsername());
        if (null == manager || !params.getPassword().equals(manager.getPassword()))
            return errorMessage(MessageCode.code_444, "用户名或密码出错");

        String tokenStr = TokenParams.getTokenStr(new UserToken(manager.getId()));
        AdminLoginModel model = new AdminLoginModel(tokenStr, manager.getName(), manager.getMobile(), manager.getRole(), manager.getId());
        return successMessage(model);
    }

    @ApiOperation("登录信息获取")
    @PostMapping("/loginInfo")
    //@Authorization()
    //@CurrentUser
    public String loginInfo(@RequestBody TokenParams params) {
        final Set<ConstraintViolation<TokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        Manager manager = managerDao.findById(params.resolveUserId()).orElse(null);
        if (null == manager) return errorMessage(MessageCode.code_404, "用户不存在");

        String tokenStr = TokenParams.getTokenStr(new UserToken(manager.getId()));
        AdminLoginModel model = new AdminLoginModel(tokenStr, manager.getName(), manager.getMobile(), manager.getRole(), manager.getId());
        return successMessage(model);
    }

    @ApiOperation("登录用户更改密码")
    @PostMapping("/changePwd")
    public String changePwd(@RequestBody ChangePasswordParams params) {
        final Set<ConstraintViolation<ChangePasswordParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        final long userId = params.resolveUserId();
        if (0 == userId) return errorMessage(MessageCode.code_777);
        final Manager manager = managerDao.findById(userId).orElse(null);
        if (null == manager) return errorMessage(MessageCode.code_777);
        if (!params.getOldPwd().equals(manager.getPassword())) return errorMessage(MessageCode.code_444, "旧密码不正确");

        if (!params.getNewPwd().equals(params.getNewPwd2())) return errorMessage(MessageCode.code_444, "两次输入的新密码不相符");
        if (params.getNewPwd().equals(params.getOldPwd())) return errorMessage(MessageCode.code_444, "新密码不能与旧密码相同");
        manager.setPassword(params.getNewPwd());
        managerDao.save(manager);

        return successMessage();
    }

    @ApiOperation("新建或修改后台用户")
    @PostMapping("/edit")
    public String edit(@RequestBody ManagerEditParams params) {
        final Set<ConstraintViolation<ManagerEditParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        Manager manager = new Manager(params.getMobile(), params.getPassword());
        if (params.getManagerId() > 0) {
            manager = managerDao.findById(params.getManagerId()).orElse(null);
            if (null == manager) return errorMessage(MessageCode.code_404, "您修改的管理员账号不存在");
        } else {
            if (StringUtils.isEmpty(params.getMobile()) || StringUtils.isEmpty(params.getPassword())) {
                return errorMessage(MessageCode.code_444, "新增账号必须填写账号和密码！");
            }
            if (params.getMobile().length() < 5 || params.getPassword().length() < 5) {
                return errorMessage(MessageCode.code_444, "账号或密码长度必须大于5位！");
            }
            Manager managerByUsername = managerDao.findManagerByMobile(params.getMobile());
            if (null != managerByUsername) return errorMessage(MessageCode.code_444, "该账号名已被使用！");
        }

        final PropertiesLoader propertiesLoader = Global.getApplicationProperties();
        String defaultUsername = propertiesLoader.getProperty("app.admin.account");
        if (defaultUsername.equals(manager.getMobile())) return errorMessage(MessageCode.code_444, "系统默认账号不可更改");

        if (!StringUtils.isEmpty(params.getPassword())) {
            manager.setPassword(params.getPassword());
        }
        manager.setRole(params.getRole());

        manager.setName(params.getName());
        manager.setContactName(params.getContactName());
        manager.setContactMobile(params.getContactMobile());
        manager.setBankContactName(params.getBankContactName());
        manager.setBankContactMobile(params.getBankContactMobile());
        managerDao.save(manager);

        if (Role.developer.equals(manager.getRole())) {
            Building building = buildingDao.findTop1ByManager(manager);
            if (null == building) {
                building = new Building("", manager);
                buildingDao.save(building);
            }
        }

        globalService.clearRedisManagerStored(manager.getId());

        return successMessage(manager);
    }

    @ApiOperation("禁用或启用后台用户")
    @PostMapping("/enable")
    public String enable(@RequestBody AdminEnableParams params) {
        final Set<ConstraintViolation<AdminEnableParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        Manager manager = managerDao.findById(params.getAdminId()).orElse(null);
        if (null == manager) return errorMessage(MessageCode.code_404, "您修改的管理员账号不存在");

        final PropertiesLoader propertiesLoader = Global.getApplicationProperties();
        String defaultUsername = propertiesLoader.getProperty("app.admin.account");
        if (defaultUsername.equals(manager.getMobile())) return errorMessage(MessageCode.code_444, "系统默认账号不可更改");
        manager.setDisable(params.isEnable() ? 0 : JodaUtils.getTimestamp());
        managerDao.save(manager);
        return successMessage(manager);
    }

    @ApiOperation("后台用户详情")
    @PostMapping("/detail")
    public String detail(@RequestBody IdParams params) {
        final Set<ConstraintViolation<IdParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        Manager manager = managerDao.findById(params.getTargetId()).orElse(null);
        if (null == manager) return errorMessage(MessageCode.code_404, "您查看的后台用户不存在");
        return successMessage(manager);
    }

    @ApiOperation("删除后台用户")
    @PostMapping("/delete")
    public String delete(@RequestBody IdTokenParams params) {
        final Set<ConstraintViolation<IdTokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        Manager manager = managerDao.findById(params.getTargetId()).orElse(null);
        if (null == manager) return errorMessage(MessageCode.code_404, "您删除的后台用户不存在");
        final PropertiesLoader propertiesLoader = Global.getApplicationProperties();
        String defaultUsername = propertiesLoader.getProperty("app.admin.account");
        if (defaultUsername.equals(manager.getMobile())) return errorMessage(MessageCode.code_444, "系统默认账号不可更改");
        manager.setRemoved(JodaUtils.getTimestamp());
        managerDao.save(manager);
        return successMessage();
    }

    @ApiOperation("后台用户账号列表")
    @PostMapping("/list")
    public String list(@RequestBody AdminPagingParams params) {
        final Set<ConstraintViolation<AdminPagingParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        Specification<Manager> specification = (Specification<Manager>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(criteriaBuilder.equal(root.get("removed"), 0));
            if (!StringUtils.isEmpty(params.getName())) {
                predicates.add(criteriaBuilder.like(root.get("name"), "%" + params.getName() + "%"));
            }
            if (null != params.getRole()) {
                predicates.add(criteriaBuilder.equal(root.get("role"), params.getRole()));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        Page<Manager> page = managerDao.findAll(specification, PageRequest.of(params.getPage(), params.getLimit(), new Sort(Sort.Direction.DESC, "id")));
        List<Manager> list = new ArrayList<>();
        page.map(manager -> {
            list.add(manager);
            return manager;
        });
        return successMessage(list, new KeyValue("page", params.getPage()), new KeyValue("total", page.getTotalElements()));
    }
}
